<template>
  <ScrollContainer ref="wrapperRef">
    <div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip">
      <slot></slot>
    </div>
  </ScrollContainer>
</template>
<script lang="ts">
import type {CSSProperties} from 'vue';
import {
  defineComponent,
  computed,
  ref,
  watchEffect,
  unref,
  watch,
  onMounted,
  nextTick,
  onUnmounted,
} from 'vue';
import {useWindowSizeFn} from '@xueyi/hooks';
import {type AnyFunction} from '@xueyi/types';
import {ScrollContainer} from '/@/components/Container';
import {createModalContext} from '../hooks/useModalContext';
import {useMutationObserver} from '@vueuse/core';

const props = {
  loading: {type: Boolean},
  useWrapper: {type: Boolean, default: true},
  modalHeaderHeight: {type: Number, default: 57},
  modalFooterHeight: {type: Number, default: 74},
  minHeight: {type: Number, default: 200},
  height: {type: Number},
  footerOffset: {type: Number, default: 0},
  visible: {type: Boolean},
  fullScreen: {type: Boolean},
  loadingTip: {type: String},
};

export default defineComponent({
  name: 'ModalWrapper',
  components: {ScrollContainer},
  inheritAttrs: false,
  props,
  emits: ['height-change', 'ext-height'],
  setup(props, {emit}) {
    const wrapperRef = ref(null);
    const spinRef = ref(null);
    const realHeightRef = ref(0);
    const minRealHeightRef = ref(0);

    let realHeight = 0;

    let stopElResizeFn: AnyFunction = () => {
    };

    useWindowSizeFn(setModalHeight.bind(null, false));

    useMutationObserver(
      spinRef,
      () => {
        setModalHeight();
      },
      {
        attributes: true,
        subtree: true,
      },
    );

    createModalContext({
      redoModalHeight: setModalHeight,
    });

    const spinStyle = computed((): CSSProperties => {
      return {
        minHeight: `${props.minHeight}px`,
        [props.fullScreen ? 'height' : 'maxHeight']: `${unref(realHeightRef)}px`,
      };
    });

    watchEffect(() => {
      props.useWrapper && setModalHeight();
    });

    watch(
      () => props.fullScreen,
      (v) => {
        setModalHeight();
        if (!v) {
          realHeightRef.value = minRealHeightRef.value;
        } else {
          minRealHeightRef.value = realHeightRef.value;
        }
      },
    );

    onMounted(() => {
      const {modalHeaderHeight, modalFooterHeight} = props;
      emit('ext-height', modalHeaderHeight + modalFooterHeight);
    });

    onUnmounted(() => {
      stopElResizeFn && stopElResizeFn();
    });

    async function scrollTop() {
      nextTick(() => {
        const wrapperRefDom = unref(wrapperRef);
        if (!wrapperRefDom) return;
        (wrapperRefDom as any)?.scrollTo?.(0);
      });
    }

    async function setModalHeight() {
      // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
      // 加上这个,就必须在使用的时候传递父级的visible
      if (!props.visible) return;
      const wrapperRefDom = unref(wrapperRef);
      if (!wrapperRefDom) return;

      const bodyDom = (wrapperRefDom as any).$el.parentElement;
      if (!bodyDom) return;
      bodyDom.style.padding = '0';
      await nextTick();

      try {
        const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
        if (!modalDom) return;

        const modalRect = getComputedStyle(modalDom as Element).top;
        const modalTop = Number.parseInt(modalRect);
        let maxHeight =
          window.innerHeight -
          modalTop * 2 +
          (props.footerOffset! || 0) -
          props.modalFooterHeight -
          props.modalHeaderHeight;

        // 距离顶部过进会出现滚动条
        if (modalTop < 40) {
          maxHeight -= 26;
        }
        await nextTick();
        const spinEl: any = unref(spinRef);

        if (!spinEl) return;
        await nextTick();
        // if (!realHeight) {
        realHeight = spinEl.scrollHeight;
        // }

        if (props.fullScreen) {
          realHeightRef.value =
            window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 28;
        } else {
          realHeightRef.value = props.height
            ? props.height
            : realHeight > maxHeight
              ? maxHeight
              : realHeight;
        }
        emit('height-change', unref(realHeightRef));
      } catch (error) {
        console.log(error);
      }
    }

    return {wrapperRef, spinRef, spinStyle, scrollTop, setModalHeight};
  },
});
</script>
